package source.repo;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import source.entity.Config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component
@Scope("prototype") // final问题
public class Generator {
    // 定义配置集
    AutoGenerator mpg = new AutoGenerator();
    StrategyConfig strategy = new StrategyConfig();
    TemplateConfig tc = new TemplateConfig();
    GlobalConfig gc = new GlobalConfig();
    DataSourceConfig dsc = new DataSourceConfig();
    PackageConfig pc = new PackageConfig();
    InjectionConfig cfg ;

    public void setDsc(Config config) {
        dsc.setUrl(config.getDbUrl());
        dsc.setDriverName(config.getDbDriver());
        dsc.setUsername(config.getDbUserName());
        dsc.setPassword(config.getDbPwd());
        dsc.setDbType(DbType.MYSQL);
    }

    public void setGc(Config config) {
        gc.setAuthor(config.getAuthor());
        //  /+module+/src/main/java/
        gc.setOutputDir(config.getProjectPath() +config.getModule_name()+config.getSrc());
        gc.setOpen(false);
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        gc.setFileOverride(false);
        gc.setIdType(IdType.ASSIGN_ID);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(false);
    }

    public void setPc(Config config) {
        pc.setParent(config.getPackage_dir()); //基本路径
        //pc.setModuleName(module_name);
        pc.setEntity("entity");
        pc.setService("service");
        pc.setController("controller");
        pc.setMapper("mapper");

        cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // 自定义属性注入
                this.setMap((Map<String, Object>) JSON.toJSON(config));
            }
        };
        this.setCustomCfg(config);
    }

    private void setCustomCfg(Config config) {
        List<FileOutConfig> focList = new ArrayList<>();
        //自定义主类  并首字母大写
        char[] cs = config.getModule_name().split("-")[1].toCharArray();
        cs[0] -= 32;
        focList.add(new FileOutConfig(config.getTempate_path()+"app.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return config.getProjectPath() + config.getModule_name()+ config.getSrc()+config.getPackage_dir_dis() +"/"+ String.valueOf(cs) +"Application.java";
            }
        });

        // 自定义app.yml
        focList.add(new FileOutConfig(config.getTempate_path()+"applicationYml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return  config.getProjectPath() + config.getModule_name()+config.getResource() +"application.yml";
            }
        });

        if(config.isNacos()){
            // 自定义bootstrap.yml
            focList.add(new FileOutConfig(config.getTempate_path()+"bootstrapYml.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getResource() +"bootstrap.yml";
                }
            });
            // 自定义bootstrap.yml
            focList.add(new FileOutConfig(config.getTempate_path()+"config.properties.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getResource() +"config.properties";
                }
            });
        }

        if(config.isOpenFeign() || config.isNacos()|| config.isAsync() || config.isScheduled()){

            // 自定义SpringCloudConf
            focList.add(new FileOutConfig(config.getTempate_path()+"SpringCloudConf.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return  config.getProjectPath() + config.getModule_name()+config.getSrc() +config.getPackage_dir_dis()+"/"+config.getCfgName()+"/SpringCloudConf.java";
                }
            });
         }


        if (config.isMybatis()) {
            // 自定义xml输出配置
            focList.add(new FileOutConfig(config.getTempate_path()+"mapper.xml.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义xml 文件名和生成路径
                    return config.getProjectPath() +config.getModule_name()+config.getResource() +"mapper/"+tableInfo.getEntityName()+"Mapper.xml";
                }
            });
            // 自定义mybatis-plus  conf
            focList.add(new FileOutConfig(config.getTempate_path()+"mybatisConfig.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return  config.getProjectPath() + config.getModule_name()+config.getSrc() +config.getPackage_dir_dis()+"/"+config.getCfgName()+"/MybatisPlusConf.java";
                }
            });
        }


        if (config.isDistribution()) {
            // 自定义 Res结果集  默认使用依赖的形式
            focList.add(new FileOutConfig(config.getTempate_path()+"result.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return  config.getProjectPath() + config.getDis_mod_name() + config.getSrc()+config.getPackage_dir_dis()+"/common"+"/Result.java";
                }
            });

            // 自定义 Res状态
            focList.add(new FileOutConfig(config.getTempate_path()+"reStat.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getDis_mod_name() + config.getSrc() + config.getPackage_dir_dis()+"/common"+"/ReStat.java";
                }
            });
        }

        if(config.isOpenFeign()){
            // 自定义 feign
            focList.add(new FileOutConfig(config.getTempate_path()+"feign.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath()+ config.getModule_name()+ config.getSrc()+config.getPackage_dir_dis()+"/feign/I"+config.getFeignService()+"RemoteService.java";
                }
            });
        }

        if(config.isRedis() || config.isRedisson() || config.isSpringCache()){
            // 自定义  本地 redisUtil
            focList.add(new FileOutConfig(config.getTempate_path()+"redisUtil.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath()+ config.getModule_name()+ config.getSrc()+config.getPackage_dir_dis()+"/util"+"/RedisUtil.java";
                }
            });
            // redis 本地  序列化
            focList.add(new FileOutConfig(config.getTempate_path()+"redisCfg.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath()+ config.getModule_name()+ config.getSrc()+config.getPackage_dir_dis()+"/"+config.getCfgName()+"/RedisConf.java";
                }
            });
        }

        if(config.isSpringTest()){
            // 自定义 feign
            focList.add(new FileOutConfig(config.getTempate_path()+"springTest.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getTestSrc() +config.getPackage_dir_dis()+"/"+ String.valueOf(cs) +"ApplicationTest.java";
                }
            });
        }

        if(config.isGlobalException()){
            // 自定义 feign
            focList.add(new FileOutConfig(config.getTempate_path()+"globalExceptionHandler.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getSrc() +config.getPackage_dir_dis()+"/" + config.getCfgName() +"/GlobalExceptionConf.java";
                }
            });
        }

        if(config.isRabbitMQ()){
            // 自定义 feign
            focList.add(new FileOutConfig(config.getTempate_path()+"rabbitMq.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getSrc() +config.getPackage_dir_dis()+"/" + config.getCfgName() +"/RabbitMqConf.java";
                }
            });
        }

        if(config.isBaseController()){
            // 自定义 feign
            focList.add(new FileOutConfig(config.getTempate_path()+"baseCon.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getSrc() +config.getPackage_dir_dis()+"/" + config.getCfgName() +"/BaseControllerConf.java";
                }
            });
        }

        if(config.isCors()){
            // 自定义 feign
            focList.add(new FileOutConfig(config.getTempate_path()+"corsConf.java.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config.getProjectPath() + config.getModule_name()+config.getSrc() +config.getPackage_dir_dis()+"/" + config.getCfgName() +"/CORSFilterConf.java";
                }
            });
        }


        cfg.setFileOutConfigList(focList);
    }

    public void setStrategy(Config config) {
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setTablePrefix(config.getT_prefix());
        strategy.setRestControllerStyle(true);
        String[] str= new String[config.tables.size()];
        strategy.setInclude(config.tables.toArray(str));
        Arrays.stream(config.tables.toArray(str)).forEach(System.out::println);
        strategy.setEntityLombokModel(true);
        strategy.setChainModel(true);
        strategy.setRestControllerStyle(true);
        TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);//自动填充时间策略
        TableFill gmtUpdate = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills =new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtUpdate);
        strategy.setTableFillList(tableFills);
        //        逻辑删除
        //        strategy.setLogicDeleteFieldName("deleted");
        //        乐观锁
        //        strategy.setVersionFieldName("version");
        //        strategy.setRestControllerStyle(true);
        //        strategy.setControllerMappingHyphenStyle(true);
        //        strategy.setTablePrefix(pc.getModuleName() + "_");
    }

    public void setTc(Config config) {
        if (!config.isMybatis()) {
            tc.setEntity(null);
            tc.setMapper(null);
            tc.setController(config.getTempate_path()+"controller.java");
            tc.setService(null);
            tc.setServiceImpl(null);
            tc.setXml(null); // 不生成xml转而使用自定义策略

        }else {
            tc.setEntity(config.getTempate_path()+"entity.java");
            tc.setMapper(config.getTempate_path()+"mapper.java");
            tc.setController(config.getTempate_path()+"controller.java");
            tc.setService(config.getTempate_path()+"service.java");
            tc.setServiceImpl(config.getTempate_path()+"serviceImpl.java");
            tc.setXml(null); // 不生成xml转而使用自定义策略
        }

    }

    public boolean startGenerate(Config config){
        this.setDsc(config);
        this.setGc(config);
        this.setPc(config);
        this.setStrategy(config);
        this.setTc(config);

        mpg.setStrategy(strategy);
        mpg.setCfg(cfg);
        mpg.setPackageInfo(pc);
        mpg.setDataSource(dsc);
        mpg.setGlobalConfig(gc);
        mpg.setTemplate(tc);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
        return true;
    }
}
